package cn.iocoder.yudao.module.vos.job;

import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.module.vos.dal.mysql.tenantrequestlog.TenantRequestLogMapper;
import cn.iocoder.yudao.module.vos.service.marketingscore.admin.MarketingScoreService;
import cn.iocoder.yudao.module.vos.utils.CdrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

@Component
@Slf4j
public class ScoreTableJob implements JobHandler {

    @Resource
    private MarketingScoreService marketingScoreService;

    @Resource
    private TenantRequestLogMapper tenantRequestLogMapper;

    private static final DateTimeFormatter YMD8 = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final DateTimeFormatter YM6  = DateTimeFormatter.ofPattern("yyyyMM");

    /** 月表前缀（模板：submeter_tenant_request_log_yyyyMM） */
    private static final String TENANT_LOG_TABLE_PREFIX = "submeter_tenant_request_log_";

    /** 入参可能是 yyyyMMdd 或 yyyy-MM-dd，转换为 8 位 */
    public static String toDay8(String s) {
        String t = s == null ? "" : s.trim();
        t = t.contains("-") ? t.replace("-", "") : t;
        if (!t.matches("\\d{8}")) throw new IllegalArgumentException("INVALID_DATE_FORMAT: " + s);
        return t;
    }

    public static String scoreTable(String day8) {
        return "submeter_marketing_score_" + day8;
    }

    /** 生成租户日志分表名（yyyyMM） */
    public static String tenantLogTable(String ym6) {
        return TENANT_LOG_TABLE_PREFIX + ym6;
    }

    /** 幂等创建单个月表：调用 Mapper 的 createTableIfNotExists */
    private void ensureTenantLogTable(String ym6) {
        if (ym6 == null || !ym6.matches("\\d{6}")) {
            throw new IllegalArgumentException("INVALID_MONTH_FORMAT: " + ym6);
        }
        String tableName = tenantLogTable(ym6);
        tenantRequestLogMapper.createTableIfNotExists(tableName);
    }

    /**
     * 创建从【过去 pastMonths 个月】到【未来 futureMonths 个月】（均含当月边界）的租户日志月表。
     * 例如：pastMonths=2, futureMonths=4 -> [当月-2, 当月-1, 当月, 当月+1, ..., 当月+4] 共 7 个月。
     */
    private String ensureTenantLogTablesWindow(int pastMonths, int futureMonths) {
        if (pastMonths < 0 || futureMonths < 0) {
            throw new IllegalArgumentException("pastMonths/futureMonths 必须为非负整数");
        }
        StringBuilder sb = new StringBuilder();
        LocalDate baseMonth = LocalDate.now(CdrUtil.ZONE).withDayOfMonth(1);
        LocalDate start = baseMonth.minusMonths(pastMonths);
        LocalDate end   = baseMonth.plusMonths(futureMonths);

        for (LocalDate m = start; !m.isAfter(end); m = m.plusMonths(1)) {
            String ym6 = m.format(YM6);
            String tbl = tenantLogTable(ym6);
            try {
                ensureTenantLogTable(ym6);
                String line = "ensure " + tbl + " OK";
                sb.append(line).append('\n');
                log.info(line);
            } catch (Exception e) {
                String line = "ensure " + tbl + " FAIL: " + e.getMessage();
                sb.append(line).append('\n');
                log.warn(line, e);
            }
        }
        return sb.toString().trim();
    }

    /**
     * 执行规则：
     * 1) 每次都会创建【当月往前 2 个月、往后 4 个月】的租户日志月表（submeter_tenant_request_log_yyyyMM）。
     * 2) param 为空：创建今天（1 天）的营销评分分表；
     *    param 为正整数 n：创建今天起往前 n 天（含今天）的营销评分分表。
     */
    @Override
    public String execute(String param) {
        StringBuilder out = new StringBuilder();

        // 1) 先创建租户请求日志月表：当月-2 ~ 当月+4
        out.append("[tenant-request-log monthly]\n");
        out.append(ensureTenantLogTablesWindow(2, 4)).append('\n');

        // 2) 再处理营销评分按天分表
        int days;
        try {
            days = (param == null || param.trim().isEmpty()) ? 1 : Integer.parseInt(param.trim());
            if (days <= 0) {
                out.append("参数必须为正整数天数");
                return out.toString();
            }
        } catch (NumberFormatException e) {
            out.append("参数必须为正整数天数");
            return out.toString();
        }

        LocalDate today = LocalDate.now(CdrUtil.ZONE);
        out.append("[marketing-score daily]\n");
        for (int i = 0; i < days; i++) {
            LocalDate d = today.minusDays(i);
            String day8 = d.format(YMD8);
            try {
                String result = marketingScoreService.ensureScoreTable(day8);
                out.append(result);
                if (i < days - 1) out.append('\n');
            } catch (Exception e) {
                String msg = "ensure " + scoreTable(day8) + " FAIL: " + e.getMessage();
                log.warn(msg, e);
                out.append(msg);
                if (i < days - 1) out.append('\n');
            }
        }
        return out.toString();
    }

    // 本地快速测试
    public static void main(String[] args) {
        System.out.println(toDay8("2023-08-01")); // 20230801
    }
}